package com.zhihuishu.micro.course.service.impl;

import com.zhihuishu.micro.course.dto.TreenityDto;
import com.zhihuishu.micro.course.service.TreenityDBService;
import com.zhihuishu.micro.course.service.TreenityRedisService;
import com.zhihuishu.micro.course.service.TreenityService;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author Jiangli
 * @date 2016/10/20 9:33
 *
 * @see TreenityService
 */
public abstract class BaseTreenityServiceImpl<DTO extends TreenityDto> extends  BaseService implements TreenityService<DTO> {
    protected abstract TreenityDBService<DTO,?> getDBService();
    protected abstract Class<DTO> getDTOClass();
    protected abstract TreenityRedisService<DTO> getRedisService();

    /**
     * 取dto列表时默认按getRank的值asc排序
     * 子类按需实现
     */
    protected  Comparator<? super DTO> getDtoListSorter(){
        return new RankSorter();
    }

    protected  String getDTOName(){
        if (getDTOClass() != null) {
            return getDTOClass().getSimpleName();
        }
        return "unknown dto name...";
    }

    @Override
    public DTO detail(Integer dtoId) {
        DTO detail = getRedisService().detail(dtoId);
        if (detail == null) {
            log.debug("start query detail in db ,id:[{}] !" ,String.valueOf(dtoId) ) ;

            detail = getDBService().detail(dtoId);

            getRedisService().updateObjectCache(detail);
        } else {
            log.debug("detail found in redis ,id:[{}] !" ,String.valueOf(dtoId) ) ;
        }
        return detail;
    }

    @Override
    public void update(DTO dto, long updateUserId) {
        Assert.notNull(dto);
        Integer dtoId = dto.getId();
        Assert.notNull(dtoId);

        // 更新数据库中的章
        getDBService().update(dto,updateUserId);

        //直接查库，然后更新缓存
        DTO detailInDB = getDBService().detail(dtoId);
        log.debug("update {} from params:[{}]!" ,getDTOName(),String.valueOf(dto)) ;
        log.debug("update {} from db:[{}]!" ,getDTOName(),String.valueOf(detailInDB) ) ;

        getRedisService().update(detailInDB,updateUserId);

        log.warn("执行更新dto:[{}]，更新人[{}]!" , dtoId,updateUserId) ;
    }

    @Override
    public void delete(Integer dtoId, long deleteUserId) {
        Assert.notNull(dtoId, "dtoId不能为空");

        getDBService().delete(dtoId,deleteUserId);

        DTO detail = detail(dtoId);

        //remove relationship
        if(detail != null && !StringUtils.isEmpty(detail.getOneToManyId())){
            getRedisService().deleteRelationShip(detail.getOneToManyId(),dtoId);
        }

        getRedisService().delete(dtoId,deleteUserId);



    }



    @Override
    public Integer create(DTO dto ,long creator) {

        Integer dtoId = getDBService().create(dto, creator);
        log.warn("执行create  generatedId:[{}]" , dtoId) ;
        getRedisService().create(dto,creator);

        return dtoId ;
    }

    @Override
    public List<DTO> list(final long oneToManyId) {
        List<Integer> dtoIdList = listDtoIds(oneToManyId);

        final List<DTO> dto = list(dtoIdList);

        return dto.isEmpty() ? null : dto ;
    }

    @Override
    public List<DTO> list(final List<Integer> dtoIdList) {
        final List<DTO> dtoList = new ArrayList<DTO>() ;
        if (CollectionUtils.isEmpty(dtoIdList)) {
            return dtoList;
        }

        //not null,may be empty
        final List<DTO> redisList = getRedisService().list(dtoIdList);

        boolean updateCache = false;
        if(CollectionUtils.isEmpty(redisList)) {
            //all in db
            updateCache = true;

            List<DTO> pureDBList = getDBService().list(dtoIdList);
            dtoList.addAll(pureDBList);

            log.debug("pureDB (dto list)-{} size:[{}] !" ,getDTOName(),pureDBList.size() ) ;
        } else if(redisList.size() != dtoIdList.size()){
            //part in db&part in redis
            updateCache = true;

            List<Integer> restQueryDBList = new LinkedList<Integer>(dtoIdList);
            for (DTO chapterInRedis : redisList) {
                restQueryDBList.remove(chapterInRedis.getId());
            }
            List<DTO> partInDB = getDBService().list(restQueryDBList);

            dtoList.addAll(redisList);
            dtoList.addAll(partInDB);


            log.debug("partDB (dto list)-{} size:[{}] !" ,getDTOName(),partInDB.size() ) ;
            log.debug("partRedis (dto list)-{} size:[{}] !" ,getDTOName(),redisList.size() ) ;
        } else {
            //all in redis
            dtoList.addAll(redisList);

            log.debug("pureRedis (dto list)-{} size:[{}] !" ,getDTOName(),redisList.size() ) ;
        }


        if(updateCache){
            getRedisService().updateObjectListCache(dtoList);
        }

        // 默认按rank值排序
        Comparator<? super DTO> sorter = getDtoListSorter();
        if(sorter != null && !CollectionUtils.isEmpty(dtoList)) {
            Collections.sort(dtoList , sorter);
        }

        return dtoList;
    }

    @Override
    public  List<Integer> listDtoIds(final long oneToManyId) {
        List<Integer> dtoIdList = getRedisService().listDtoIds(oneToManyId);

        if(CollectionUtils.isEmpty(dtoIdList)){
            dtoIdList =  getDBService().listDtoIds(oneToManyId);

            getRedisService().updateIdListCache(oneToManyId,dtoIdList);

            log.debug("pureDB   (id list)-{} size:[{}] for oneToManyId:[{}]!" ,getDTOName(),dtoIdList.size() , oneToManyId) ;
        } else {
            log.debug("pureRedis  (id list)-{} size:[{}] for oneToManyId:[{}]!" ,getDTOName(),dtoIdList.size() , oneToManyId) ;
        }
        return dtoIdList;
    }


}
